use std::collections::BTreeMap;
use hmac::{Hmac, Mac};
use jwt::{AlgorithmType, Header, SignWithKey, Token, VerifyWithKey};
use sha2::{Sha256, Sha384};

// jwt 使用参考：    https://docs.rs/jwt/0.16.0/jwt
// 用于生成和验证JSON Web令牌（JWT）的 Rust 库。
pub fn jwt_demo() {
    // 签名，生成一个 JWT 令牌
    // 如果你不关心这个标头，只要标头经过验证，只需几个特征就可以完成签名和验证。
    // 能够签名和验证令牌的算法。默认情况下，只支持hmac crate的hmac类型。有关更多算法，请启用openssl功能并参阅openssl模块。明确不支持none算法。
    let key: Hmac<Sha256> = Hmac::new_from_slice(b"some-secret").unwrap();
    // let hs256_key: Hmac<Sha256> = Hmac::new_from_slice(b"some-secret").unwrap();
    // 这里的 claims 是一个 BTreeMap，可以包含任意数量的键值对
    let mut claims = BTreeMap::new();
    claims.insert("sub", "someone");
    // 使用签名密钥生成一个 JWT 令牌
    let token_str = claims.sign_with_key(&key).unwrap();
    println!("token: {}", token_str);
    assert_eq!(token_str, "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzb21lb25lIn0.5wwE1sBrs-vftww_BGIuTVDeHtc1Jsjo-fiHhDwR8m0");

    // 验证，验证一个 JWT 令牌是否有效
    let key: Hmac<Sha256> = Hmac::new_from_slice(b"some-secret").unwrap();
    let token_str = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzb21lb25lIn0.5wwE1sBrs-vftww_BGIuTVDeHtc1Jsjo-fiHhDwR8m0";
    // 使用签名密钥验证 JWT 令牌的有效性并获取数据载体
    let claims: BTreeMap<String, String> = token_str.verify_with_key(&key).unwrap();
    assert_eq!(claims["sub"], "someone");



    // 签名，自定义 Header 和 Claims， 标头和声明都必须实现 serde::Serialize。
    // 你可以通过 Header 和 Claims 结构体来获取 JWT 令牌中的信息。
    // 如果需要自定义标头，可以使用Token结构。为了方便起见，为所有常用定义的字段提供了Header结构，但可以使用实现JoseHeader的任何类型。
    // 创建一个签名的加密密钥
    let key: Hmac<Sha384> = Hmac::new_from_slice(b"some-secret").unwrap();
    // 自定义 Header
    let header = Header {
        algorithm: AlgorithmType::Hs384,
        ..Default::default()
    };
    // 自定义 Claims 数据载体
    let mut claims = BTreeMap::new();
    claims.insert("sub", "someone");

    let token = Token::new(header, claims).sign_with_key(&key).unwrap();
    assert_eq!(token.as_str(), "eyJhbGciOiJIUzM4NCJ9.eyJzdWIiOiJzb21lb25lIn0.WM_WnPUkHK6zm6Wz7zk1kmIxz990Te7nlDjQ3vzcye29szZ-Sj47rLNSTJNzpQd_");

    // 验证，验证自定义 Header 和 Claims
    let key: Hmac<Sha384> = Hmac::new_from_slice(b"some-secret").unwrap();
    let token_str = "eyJhbGciOiJIUzM4NCJ9.eyJzdWIiOiJzb21lb25lIn0.WM_WnPUkHK6zm6Wz7zk1kmIxz990Te7nlDjQ3vzcye29szZ-Sj47rLNSTJNzpQd_";
    // 使用签名密钥验证 JWT 令牌的有效性并获取数据载体
    let token: Token<Header, BTreeMap<String, String>, _> = VerifyWithKey::verify_with_key(token_str, &key).unwrap();
    let header = token.header();
    let claims = token.claims();

    assert_eq!(header.algorithm, AlgorithmType::Hs384);
    assert_eq!(claims["sub"], "someone");
}